package cc.eddic.practice.spring.web;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * HttpServletRequest 工具类
 */
@Slf4j
@Component
public class RequestUtils {

    private RequestUtils() {
    }

    public static final String UNKNOWN_IP = "unknown";

    private static final String HEADER_X_FORWARDED_FOR = "x-forwarded-for";
    private static final String HEADER_PROXY_CLIENT_IP = "Proxy-Client-IP";
    private static final String HEADER_WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP";
    private static final String HEADER_USER_AGENT = "User-Agent";
    public static final String HEADER_AUTHORIZATION = "Authorization";
    public static final String HEADER_REFERER = "Referer";


    /**
     * 获取访问的完整 URL，包含 Query Parameters
     *
     * @param request HttpServletRequest
     * @return 完整 URL
     */
    public static String getFullUrl(HttpServletRequest request) {
        StringBuilder requestURL = new StringBuilder(request.getRequestURL().toString());
        String queryString = request.getQueryString();

        if (StringUtils.hasText(queryString)) {
            requestURL.append('?').append(queryString);
        }
        return requestURL.toString();
    }

    /**
     * 取 IP 地址
     *
     * @param request HttpServletRequest
     * @return IP 地址
     */
    public static String getRequestIp(HttpServletRequest request) {
        String ip = request.getHeader(HEADER_X_FORWARDED_FOR);
        log.trace("{}: {}", HEADER_X_FORWARDED_FOR, ip);

        if (!StringUtils.hasText(ip) || ip.equalsIgnoreCase(UNKNOWN_IP)) {
            ip = request.getHeader(HEADER_PROXY_CLIENT_IP);
            log.trace("{}: {}", HEADER_PROXY_CLIENT_IP, ip);
        }
        if (!StringUtils.hasText(ip) || ip.equalsIgnoreCase(UNKNOWN_IP)) {
            ip = request.getHeader(HEADER_WL_PROXY_CLIENT_IP);
            log.trace("{}: {}", HEADER_WL_PROXY_CLIENT_IP, ip);
        }
        if (!StringUtils.hasText(ip) || ip.equalsIgnoreCase(UNKNOWN_IP)) {
            ip = request.getRemoteAddr();
            log.trace("getRemoteAddr: {}", ip);
        }
        return ip;
    }

    /**
     * 取 UserAgent
     *
     * @param request HttpServletRequest
     * @return UserAgent
     */
    public static String getUserAgent(HttpServletRequest request) {
        return request.getHeader(HEADER_USER_AGENT);
    }

    /**
     * 取 Authorization
     *
     * @param request HttpServletRequest
     * @return Authorization
     */
    public static String getAuthorization(HttpServletRequest request) {
        return request.getHeader(HEADER_AUTHORIZATION);
    }

    /**
     * 取 Referer
     *
     * @param request HttpServletRequest
     * @return Referer
     */
    public static String getReferer(HttpServletRequest request) {
        return request.getHeader(HEADER_REFERER);
    }

    public static void sendError(int status, RestError error, HttpServletResponse response) {

        response.reset();
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setStatus(status);

        try {
            // https://www.baeldung.com/jackson-serialize-dates#java-8
            ObjectMapper om = new ObjectMapper();
            om.registerModule(new JavaTimeModule());
            om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

            val json = om.writeValueAsString(error);
            // https://www.baeldung.com/servlet-json-response
            val w = response.getWriter();
            w.write(json);
            w.flush();
            w.close();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
    }

}
